package com.example.customview.photoview

import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.View
import android.widget.OverScroller
import com.example.customview.R
import kotlin.math.max
import kotlin.math.min

class PhotoView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    private var bitMap: Bitmap? = null
    private var top: Float = 0f
    private var left: Float = 0f

    private var bitScale: Float = 0f
    private var smallScale:Float = 0f

    private var currentScale:Float = 0f

    private  var gestureDetector: GestureDetector

    private var translateX = 0f
    private var translateY = 0f

    private var mScroller: OverScroller
    private val paint = Paint()

    private var photoScaleGesture:ScaleGestureDetector
    private var  isScale = false

    private var beginDoubleScale = false

    init {
        bitMap = BitmapFactory.decodeResource(resources, R.mipmap.ff)
        gestureDetector = GestureDetector(getContext(),PhotoGesture())
        mScroller = OverScroller(context)
        photoScaleGesture = ScaleGestureDetector(context,PhotoScaleGesture())
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
       val scaleFraction = (currentScale-smallScale) /(bitScale-smallScale)
        canvas.translate(translateX*scaleFraction,translateY*scaleFraction)
        canvas.scale(currentScale,currentScale,width/2f,height/2f)
        bitMap?.let {
            canvas.drawBitmap(it, left, top, paint)
        }
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        top = (height - bitMap?.height!!) / 2f
        left = (width - bitMap?.width!!) / 2f

        bitMap?.let {
            if (it.width / it.height > width / height) {  // 宽高比大于屏幕宽高比 横屏显示
                bitScale = height.toFloat() /it.height
                smallScale = width.toFloat()/ it.width
            } else { //竖屏显示
                bitScale = width / it.width.toFloat()
                smallScale = height/it.height.toFloat()
            }

        }
        this.currentScale = smallScale

    }

    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        var onTouchEvent = photoScaleGesture.onTouchEvent(event)
        if (!photoScaleGesture.isInProgress){
            onTouchEvent = gestureDetector.onTouchEvent(event)
        }
        return onTouchEvent
    }

    inner class PhotoGesture :GestureDetector.SimpleOnGestureListener(){

        override fun onScroll(
            e1: MotionEvent?,
            e2: MotionEvent,
            distanceX: Float,
            distanceY: Float
        ): Boolean {
            if (isScale){
                translateX -= distanceX
                translateY -= distanceY
                overBounds()
                invalidate()
            }


            return super.onScroll(e1, e2, distanceX, distanceY)
        }
        private fun overBounds(){
            translateX = min(translateX,(bitMap!!.width*bitScale-width)/2)
            translateX = max(translateX,-(bitMap!!.width*bitScale-width)/2)

            translateY = min(translateY,(bitMap!!.height*bitScale-height)/2)
            translateY = max(translateY,-(bitMap!!.height*bitScale-height)/2)

        }

        override fun onFling(
            e1: MotionEvent?,
            e2: MotionEvent,
            velocityX: Float,
            velocityY: Float
        ): Boolean {
            if (isScale){
                mScroller.fling(
                    translateX.toInt(), translateY.toInt(),
                    velocityX.toInt(), velocityY.toInt(),
                    -((bitMap!!.width*bitScale-width)/2f).toInt(),
                    ((bitMap!!.width*bitScale-width)/2f).toInt(),
                   - ((bitMap!!.height*bitScale-height)/2).toInt(),
                    ((bitMap!!.height*bitScale-height)/2).toInt(),
                    300,300
                    )

                postOnAnimation(FlingRunner())
            }

            return super.onFling(e1, e2, velocityX, velocityY)
        }
        inner class FlingRunner : Runnable {
            override fun run() {
                // 动画还在执行 则返回true
                if (mScroller.computeScrollOffset()) {
                    translateX = mScroller.currX.toFloat()
                    translateY = mScroller.currY.toFloat()
                    invalidate()
                    // 没帧动画执行一次，性能更好
                    postOnAnimation(this)
                }
            }
        }

        override fun onDoubleTap(e: MotionEvent): Boolean {

            isScale = !isScale
            if (isScale){
                translateX = (e.x - width / 2f) - (e.x - width / 2) * bitScale / smallScale;
                translateY = (e.y - height / 2f) - (e.y - height / 2) * bitScale / smallScale;
                overBounds()
                startAnimation().start()
            }else{
                startAnimation().reverse()
            }
            return  super.onDoubleTap(e)

        }

        override fun onDown(e: MotionEvent): Boolean {
            return true
        }
    }


    inner class PhotoScaleGesture() :ScaleGestureDetector.SimpleOnScaleGestureListener(){
        private var initScale = 0f
        override fun onScale(detector: ScaleGestureDetector): Boolean {
            if (currentScale>smallScale && !isScale || currentScale==smallScale && isScale){
                isScale = !isScale
            }
            currentScale = initScale*detector.scaleFactor
            if (currentScale<smallScale){
                currentScale = smallScale
            }
            beginDoubleScale = true
            invalidate()
            return false
        }

        override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
            initScale = currentScale
            return true
        }
    }

    fun startAnimation():ValueAnimator{
        var animation:ValueAnimator
        if (beginDoubleScale){
            beginDoubleScale = false
             animation = ValueAnimator.ofFloat(smallScale,currentScale)
        }else{
             animation = ValueAnimator.ofFloat(smallScale,bitScale)
        }

        animation.duration = 200
        animation.addUpdateListener {
            this.currentScale = it.animatedValue as Float
            invalidate()
        }
        return animation
    }

}